package models

import (
	"mime/multipart"
	"gopkg.in/mgo.v2"
	"io"
	"github.com/astaxie/beego"
	"gopkg.in/mgo.v2/bson"
	"errors"
	"bufio"
)

//保存在mongdb中的文件
type FileInfo struct {
	Id       uint64    `db:"id" description:"主键"`
	Name     string    `db:"name" description:"文件名称"`
	Size     int64     `db:"size" description:"文件大小"`
	MongDbId string    `db:"mong_db_id" description:"在 mongDb中存放的id"`
}

//增加一个文件
type AddFileInfo struct {
	Id       int
	Name     string //文件名称
	Size     int64  //文件大小
	MongDbId string //在 mongDb中存放的id
}

//根据id 查询文件内容
type FindFileInfo struct {
	Id     int

	Result FileInfoResurt
}


//查询返回
type FileInfoResurt struct {
	Total  int
	Result []FileInfo
}

var (
	URL = "" //mongodb连接字符串
	mgoSession *mgo.Session
	dataBase = ""
)

func init() {
	URL = beego.AppConfig.String("mongdburl")
	dataBase = beego.AppConfig.String("mongdburldatabase")

}

/**
 * 公共方法，获取session，如果存在则拷贝一份
 */
func getSession() *mgo.Session {
	if mgoSession == nil {
		var err error
		mgoSession, err = mgo.Dial(URL)
		if err != nil {
			panic(err) //直接终止程序运行
		}
	}
	//最大连接池默认为4096
	return mgoSession.Clone()
}


/**
 上传文件
 */
func AddFile(f multipart.File, h *multipart.FileHeader) (FileInfo, error) {

	session := getSession()
	defer session.Close()
	g := session.DB(dataBase)

	file, _ := h.Open()
	fileInfo := FileInfo{}
	if gridFile, err := g.GridFS("fs").Create(h.Filename); err != nil {
		return fileInfo, err
	} else {
		gridFile.SetMeta(f)
		gridFile.SetName(h.Filename)
		if err := writeToGridFile(file, gridFile); err != nil {
			return fileInfo, err
		}
		gridFile.Size()
		b := gridFile.Id().(bson.ObjectId).Hex()

		beego.Debug("fileId:", b)

		//保存到 fileInfo
		fileInfo.Name = h.Filename
		fileInfo.Size = gridFile.Size()
		fileInfo.MongDbId = b
		return fileInfo, nil
	}
}


/**
 删除文件
 */
func DeleteFile(fileId string) error {

	session := getSession()
	defer session.Close()
	g := session.DB(dataBase)

	gfs := g.GridFS("fs")
	if bson.IsObjectIdHex(fileId) {
		gfs.RemoveId(bson.ObjectIdHex(fileId))
	}

	return nil
}

/**
   获取文件
 */
func GetFile(fileId string) ([]byte, error) {

	session := getSession()
	defer session.Close()
	g := session.DB(dataBase)

	gfs := g.GridFS("fs")

	file, err := gfs.OpenId(bson.ObjectIdHex(fileId))
	if err != nil {
		beego.Debug(err.Error())
		//return , err
	}
	defer file.Close()

	beego.Debug(file)
	image := make([]byte, file.Size())
	_, err = file.Read(image)

	return image, err
}

func writeToGridFile(file multipart.File, gridFile *mgo.GridFile) error {

	reader := bufio.NewReader(file)
	defer func() {
		file.Close()
	}()
	// make a buffer to keep chunks that are read
	buf := make([]byte, 1024)
	for {
		// read a chunk
		n, err := reader.Read(buf)
		if err != nil && err != io.EOF {
			return errors.New("Could not read the input file")
		}
		if n == 0 {
			break
		}
		// write a chunk
		if _, err := gridFile.Write(buf[:n]); err != nil {
			return errors.New("Could not write to GridFs for " + gridFile.Name())
		}
	}
	gridFile.Close()
	return nil
}




